import componentsMap from '../utils/componentsMap';
import {cloneDeep} from '../utils/index.js';
const componentChild = {};
/**
 * 将./slots中的文件挂载到对象componentChild上
 * 文件名为key，对应JSON配置中的__config__.tag
 * 文件内容为value，解析JSON配置中的__slot__
 */
const slotsFiles = require.context('./slots', false, /\.js$/);
const keys = slotsFiles.keys() || [];
keys.forEach((key) => {
	const tag = key.replace(/^\.\/(.*)\.\w+$/, '$1');
	const value = slotsFiles(key).default;
	componentChild[tag] = value;
});

// 表单值回显
function model(dataObject, defaultValue){
	dataObject.props.value = defaultValue;
	dataObject.on.input = (val) => {
		this.$emit('input', val);
	};
}

function mountSlotFiles(h, confClone, children){
	const childObjs = componentChild[confClone.config.tag];
	if(childObjs){
		Object.keys(childObjs).forEach((key) => {
			const childFunc = childObjs[key];
			if(confClone.customSlot && confClone.customSlot[key]){
				children.push(childFunc(h, confClone, key));
			}
		});
	}
}

function emitEvents(confClone){
	['on', 'nativeOn'].forEach((attr) => {
		const eventKeyList = Object.keys(confClone[attr] || {});
		eventKeyList.forEach((key) => {
			if(typeof key === 'string'){
				confClone[attr][key] = (...arg) => this.$emit(key, arg);
			}
		});
	});
}

function buildDataObject(confClone, dataObject, formData){
	const identity = confClone.config.identity;
	Object.keys(confClone).forEach((key) => {
		const val = confClone[key];
		if(key === 'model'){
			model.call(this, dataObject, confClone.config.defaultValue);
		}else if(dataObject[key] !== undefined){
			if(
				dataObject[key] === null
				|| dataObject[key] instanceof RegExp
				|| ['boolean', 'string', 'number', 'function'].includes(
					typeof dataObject[key],
				)
			){
				dataObject[key] = val;
			}else if(Array.isArray(dataObject[key])){
				dataObject[key] = [...dataObject[key], ...val];
			}else{
				dataObject[key] = {...dataObject[key], ...val};
			}
		}else{
			dataObject.attrs[key] = val;
		}
	});
	if(identity === 'text'){
		model.call(this, dataObject, confClone.config.defaultValue);
	}
	if(
		[
			'calculate',
			'table',
			'barcode',
			'qrcode',
			'popupSelect',
			'popupTableSelect',
			'autoComplete',
		].includes(identity)
	){
		dataObject.attrs['formData'] = formData;
	}
	if(['table'].includes(identity)){
		dataObject.attrs['relations'] = this.relations;
		dataObject.attrs['model'] = confClone.model;
	}
	if(['popupAttr', 'calculate', 'relationFormAttr'].includes(identity)){
		dataObject.attrs['isStorage'] = confClone.config.isStorage;
		dataObject.attrs['defaultValue'] = confClone.config.defaultValue;
	}
	if(['relationForm', 'popupSelect'].includes(identity)){
		const {config, model} = confClone;
		if(config.isSubTable){
			dataObject.attrs['field'] = config.tableName
				? `${model}_table_${config.tableName}0`
				: model;
		}else{
			dataObject.attrs['field'] = model;
		}
	}
	if(['relationForm', 'relationFormAttr'].includes(identity)){
		dataObject.attrs.drawingList = this.formConf.fields;
	}
  // 清理属性
	clearAttrs(dataObject);
}

function clearAttrs(dataObject){
	delete dataObject.attrs.slot;
	delete dataObject.attrs.__methods__;
}

function makeDataObject(){
	return {
		class:{},
		attrs:{},
		props:{},
		domProps:{},
		nativeOn:{},
		on:{},
		style:{},
		directives:[],
		scopedSlots:{},
		slot:null,
		key:null,
		ref:null,
		refInFor:true,
	};
}
export default {
	props:{
		formConf:{
			type:Object,
			default: () => ({}),
		},
		conf:{
			type:Object,
			required:true,
		},
		formData:{
			type:Object,
			default: () => ({}),
		},
		relations:Object,
	},
	render(h){
		const dataObject = makeDataObject();
		const confClone = cloneDeep(this.conf);
		const children = this.$slots.default || [];

        // 如果slots文件夹存在与当前tag同名的文件，则执行文件中的代码
		mountSlotFiles.call(this, h, confClone, children);

        // 将字符串类型的事件，发送为消息
		emitEvents.call(this, confClone);

        // 将json表单配置转化为vue render可以识别的 “数据对象（dataObject） dataObject.props.value绑定的表单数据”
		buildDataObject.call(this, confClone, dataObject, this.formData);
		return h(componentsMap[this.conf.config.tag], dataObject, children);
	},
};